﻿    using System;
    using System.Collections.Generic;
	using System.ComponentModel;

#if WinRT
    using Windows.UI.Xaml;
#else
    using System.Windows;
#endif


namespace DailyFx.UI 
{
	/// <summary>
    ///		which is aware of its view(s).
    /// </summary>
    public interface IViewAware 
	{
        /// <summary>
        ///		Attaches a view to this with specified content the view appears .
        /// </summary>
        void AttachView ( object view, object context = null );

        /// <summary>
        ///		Gets a view previously attached to this instance.
        /// </summary>
        object GetView ( object context = null );

        /// <summary>
        ///		Raised when a view is attached.
        /// </summary>
        event EventHandler<ViewAttachedEventArgs> ViewAttached;

		/// <summary>
		///		Raises when a view is attached  .
		/// </summary>
		//	void OnViewAttached ( object view, object context );

#if WINDOWS_PHONE || WinRT
        /// <summary>
        ///		Called the first time the view's LayoutUpdated event fires after it is navigated to.
        /// </summary>
        void OnViewReady ( object view ) ;
#endif

	}

    
    public class ViewAware : IViewAware, INotifyPropertyChangedEx
	{

       	static readonly DependencyProperty PreviouslyAttachedProperty = 
			DependencyProperty.RegisterAttached( "PreviouslyAttached", typeof(bool), typeof(ViewAware), null );


		/// <summary>
		///   The view chache for this instance.
		/// </summary>
		protected readonly Dictionary<object, object> Views = new Dictionary<object, object>();

		/// <summary>
		///		Indicates whether to caches views of this .
		/// </summary>
		private bool _isViewsCached;


        /// <summary>
        ///		Indicates whether or not implementors of <see cref="IViewAware"/> should cache their views by default.
        /// </summary>
        public static bool ViewsCachedByDefault = true;


        /// <summary>
		/// 
		/// </summary>
		public ViewAware ()
			: this ( ViewsCachedByDefault )
		{ 
		}

		///<summary>
		/// 
		///</summary>
		public ViewAware ( bool viewsCached )
		{
			this.IsViewsCached = viewsCached;
		}


		///<summary>
		///		Indicates whether or not this maintains a view cache-buffer .
		///</summary>
		protected bool IsViewsCached
		{
			get 
			{
				return this._isViewsCached; 
			}
			set
			{
				this._isViewsCached = value;
				if ( !this._isViewsCached )
					Views.Clear () ;
			}
		}

		void IViewAware.AttachView ( object view, object context )
		{
			if ( this._isViewsCached )
			{
				this.Views [context ?? View.DefaultContext] = view;
			}

			var view2 = View.GetFirstNonCreatedView ( view );

			var element = view2 as FrameworkElement;
			if ( element != null && !(bool)element.GetValue( PreviouslyAttachedProperty) )
			{
				element.SetValue( PreviouslyAttachedProperty, true );
				View.CarryOnViewLoaded ( element, (s, e) => this.OnViewLoaded(s) );
			}

			this.OnViewAttached( view2, context );
			this.ViewAttached ( this, new ViewAttachedEventArgs { View = view2, Context = context });
		}


		/// <summary>
		///		Gets a view previously attached to this .
		/// </summary>
		public virtual object GetView ( object context = null )
		{
			object view;
			this.Views.TryGetValue( context ?? View.DefaultContext, out view );
			
			return view;
		}

		/// <summary>
		///   Raised when a view is attached.
		/// </summary>
		public event EventHandler<ViewAttachedEventArgs> ViewAttached = delegate { };

		/// <summary>
		///		Called when a view is attached.
		/// </summary>
		protected virtual void OnViewAttached(object view, object context)
		{
		}

		/// <summary>
		///		Called when an attached view's Loaded event fires.
		/// </summary>
		protected virtual void OnViewLoaded(object view)
		{
		}

#if WINDOWS_PHONE || WinRT
        
		void IViewAware.OnViewReady ( object view ) 
		{
            OnViewReady( view );
        }

        /// <summary>
        ///   Called the first time the page's LayoutUpdated event fires after it is navigated to.
        /// </summary>
        protected virtual void OnViewReady( object view )
		{
		}
#endif



		public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        ///		Notify using pre-made PropertyChangedEventArgs
        /// </summary>
        protected void RaisePropertyChanged ( PropertyChangedEventArgs args )
        {
            if ( this.PropertyChanged != null)
            {
                this.PropertyChanged (this, args);
            }
        }

        /// <summary>
        ///		Notify using String property name
        /// </summary>
        public void RaisePropertyChanged ( String propertyName )
        {
            if ( this.PropertyChanged != null)
            {
                this.PropertyChanged (this, new PropertyChangedEventArgs(propertyName) );
            }
        }
    }

	/// <summary>
	/// The event args for the <see cref="IViewAware.ViewAttached"/> event.
	/// </summary>
	public class ViewAttachedEventArgs : EventArgs
	{
		/// <summary>
		/// The view.
		/// </summary>
		public object View;

		/// <summary>
		/// The context.
		/// </summary>
		public object Context;
	}

}
